API(application program interface)是指程式之間具有特定規範的接口。透過這些接口可以引用其他程式來協助完成整體機能。
其實JAVA當中引用package或class的概念也與此相同。以下介紹常見的class及其method:
Object是java中所有class的父類。
裡面提供了一些通用方法
method名 | 說明 |
---|---|
boolean equals(Object obj) | 比較是否為同一個物件 |
final Class<?> getClass() | 返回此物件的class |
int hashCode() | 返回此物件的hashCode值 |
String toString() | 返回物件的描述文字列。 |
範例:
class Foo {}
class Sample7_1 {
public static void main(String[] args) {
int[] ary = {1,2,3};
Class obj1 = ary.getClass();
System.out.println(obj1.getName());
Foo foo = new Foo();
Class obj2 = foo.getClass();
System.out.println(obj2.getName());
}
}
執行結果
[I
Foo
本範例中使用getClass()取得實例化物件的來源class後,再使用getName()方法得到class的名稱。
結果的第一行中,"["表示陣列,"I"則表示int型態。合起來即為儲存int資料的陣列。
Foo則為class名稱。
Object class裡面的equals()方法用來比較兩個物件是否為同一個。然而在String類中,這個方法卻被用來比較值是否相等。
這是因為equals()方法在String類中被覆寫了的關係。
下面幾個範例,比較equals()在String,StringBuilder及Integer類中的不同。
class Sample7_2 {
public static void main(String[] args) {
String s1 = "Tom";
String s2 = new String("Tom");
String s3 = "tom";
System.out.println("s1 == s2 : " + (s1 == s2));
System.out.println("s1.equals(s2) : " + s1.equals(s2));
System.out.println("s1.equals(s3) : " + s1.equals(s3));
System.out.println("s1.equalsIgnoreCase(s3) : " + s1.equalsIgnoreCase(s3));
}
}
執行結果
s1 == s2 : false
s1.equals(s2) : true
s1.equals(s3) : false
s1.equalsIgnoreCase(s3) : true
說明
s1與s2不是同一個物件,返回false
s1與s2的值相同,返回true
s1與s3的大小寫不同,返回false
忽略大小寫,返回true
class Sample7_3 {
public static void main(String[] args) {
//StringBuilder sb1 = "Tom"; //error
StringBuilder sb2 = new StringBuilder("Tom");
StringBuilder sb3 = new StringBuilder("Tom");
System.out.println("sb2 == sb3 :" + (sb2 == sb3));
System.out.println("sb2.equals(sb3) :" + sb2.equals(sb3));
System.out.println("sb2.toString().equals(sb3.toString()) :" + sb2.toString().equals(sb3.toString()));
}
}
執行結果
sb2 == sb3 :false
sb2.equals(sb3) :false
sb2.toString().equals(sb3.toString()) :true
說明
"==" 比較是否為同一物件,傳回false。
StringBuilder的equals()未被覆寫(跟Object類一樣),比較是否為同一物件,傳回false。
要比較StringBuilder的值,可以運用toString()方法轉為String物件後,即可用equals()進行比較,傳回true。
class Sample7_4 {
public static void main(String[] args) {
Integer val1 = 1;
Integer val2 = 1;
System.out.println("val1 == val2 :" + (val1 == val2));
Integer val3 = 150;
Integer val4 = 150;
System.out.println("val3 == val4 :" + (val3 == val4));
System.out.println("val3.equals(val4) :" + val3.equals(val4));
Integer val5 = new Integer(1);
System.out.println("val1 == val5 :" + (val1 == val5));
System.out.println("val1.equals(val5) :" + val1.equals(val5));
Long val6 = new Long(150);
Double val7 = new Double(150.0);
System.out.println("val3.equals(val6) :" + val3.equals(val6));
System.out.println("val3.equals(val7) :" + val3.equals(val7));
System.out.println("val3.equals(val6.intValue()) :" + val3.equals(val6.intValue()));
System.out.println("val3.equals(val7.intValue()) :" + val3.equals(val7.intValue()));
}
}
執行結果
val1 == val2 :true
val3 == val4 :false
val3.equals(val4) :true
val1 == val5 :false
val1.equals(val5) :true
val3.equals(val6) :false
val3.equals(val7) :false
val3.equals(val6.intValue()) :true
val3.equals(val7.intValue()) :true
說明
第一行比較了val1和val2兩個物件是否為同一物件,結果傳回true。
這是因為當參照值為int形式,且值介於-128 ~127之間(儲存空間小於1 byte),則參照此值的物件,都是參照記憶體上相同的位址,即同一物件。
第二行的值為150,超過了1 byte所能保存的範圍,因此不是同一物件。需使用equals()比較值大小,才會傳回true(第三行)。
這表示Integer類和String類的equals()方法一樣,都被覆寫為比較值的方法。
第四行&第五行:使用new()方法新增物件的話,即使值相同也不會被視為同一物件。因此val1和val5不是同物件,但值相同。
第六行以後比較Long,Double及Integer等不同類型的物件,由於無法直接比較,引此傳回false。
利用intValue()方法將Long,Double類轉為Integer類之後即可進行值的比較。
toString()也是Object提供的基本方法之一,會傳回物件的class名+@+hashcode。不過依照各個class需求的不同,通常這方法會被覆寫成其他樣子。
請看以下範例:
class Foo {}
class Bar {
public String toString(){
return "This is an object made from Bar.";
}
}
class Sample7_5 {
public static void main(String[] args) {
String obj1 = "Tom";
StringBuilder obj2 = new StringBuilder("Tom");
Foo obj3 = new Foo();
Bar obj4 = new Bar();
System.out.println(obj1);
System.out.println(obj2);
System.out.println(obj3);
System.out.println(obj4);
}
}
執行結果
Tom
Tom
Foo@368239c8
This is an object made from Bar.
說明
String和StringBuilder類的toString()都被覆寫過,會傳回其保存的文字列。
沒被覆寫過的toString()會傳回物件的class名+@+hashcode。
也可以自定義要傳回的文字列。
提供數學計算的一些方法,例如:
int num1 = 100;
int num2 = 200;
int max = int Math.max(num1,num2); //傳回最大值
double randomVal = int Math.random(); //傳回小於1的隨機值
請看以下範例:
import java.util.*;
class Sample7_6 {
public static void main(String[] args) {
int[] i_array = {30,10,20,50,40};
//使用arraycopy()方法複製陣列
int[] copy = new int[3];
System.arraycopy(i_array,2,copy,0,3);
for(int val: copy){
System.out.print(val + " ");
}System.out.println();
//使用sort()方法排序
Arrays.sort(i_array);
for(int val: i_array){
System.out.print(val + " ");
}System.out.println();
//使用asList()方法
String[] s_array = {"Tom","Hill","Cathy"};
List<String> list = Arrays.asList(s_array);
//list.add("Mary");
for(String val: list){
System.out.print(val + " ");
}System.out.println();
}
}
執行結果
20 50 40
10 20 30 40 50
Tom Hill Cathy
說明
arraycopy()方法屬於System類,文法為arraycopy(來源陣列,開始位置,目標陣列,開始位置,複製的長度)
sort()方法屬於Arrays類(需先import),可依內容值的大小重新排列陣列。
asList()方法屬於Arrays類(需先import),可將陣列轉為List(固定長)。由於固定長的List無法增加長度,因此list.add("Mary");這行若執行的話會報錯。
需要可變長的列表時,使用ArrayList如下例:
List<String> list = new ArrayList<>(Arrays.asList(s_array));
list.add("Mary");
執行結果
Tom Hill Cathy Mary
此類由java.time包提供,特徵如下:
java.time包的主要class
java.time.format包的主要class
來看看日期時間的範例吧:
import java.time.*;
class Sample7_7 {
public static void main(String[] args) {
LocalDate dateNow = LocalDate.now();
LocalTime timeNow = LocalTime.now();
LocalDateTime dateTimeNow = LocalDateTime.now();
LocalDate dateOf = LocalDate.of(2021,2,25);
LocalTime TimeOf = LocalTime.of(21,3,20);
LocalDateTime dateTimeOf = LocalDateTime.of(2021,2,25,21,3,20);
LocalDate dateP = LocalDate.parse("2021-02-25");
LocalTime TimeP = LocalTime.parse("21:03:20");
LocalDateTime dateTimeP = LocalDateTime.parse("2021-02-25T21:03:20");
System.out.println("LocalDate.now :" + dateNow);
System.out.println("LocalTime.now :" + timeNow);
System.out.println("LocalDateTime.now :" + dateTimeNow);
System.out.println("LocalDate.of :" + dateOf);
System.out.println("LocalTime.of :" + TimeOf);
System.out.println("LocalDateTime.of :" + dateTimeOf);
System.out.println("LocalDate.parse :" + dateP);
System.out.println("LocalTime.parse :" + TimeP);
System.out.println("LocalDateTime.parse :" + dateTimeP);
}
}
執行結果
LocalDate.now :2021-02-25
LocalTime.now :19:24:11.679136400
LocalDateTime.now :2021-02-25T19:24:11.679136400
LocalDate.of :2021-02-25
LocalTime.of :21:03:20
LocalDateTime.of :2021-02-25T21:03:20
LocalDate.parse :2021-02-25
LocalTime.parse :21:03:20
LocalDateTime.parse :2021-02-25T21:03:20
日期格式範例
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class Sample7_8 {
public static void main(String[] args) {
LocalDateTime dt1 = LocalDateTime.now();
DateTimeFormatter fmt1 = DateTimeFormatter.ISO_DATE;
System.out.println("now() :" + dt1);
System.out.println("ISO_DATE :" + fmt1.format(dt1));
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
String target = "2021/02/25 21:03:20";
LocalDateTime dt2 = LocalDateTime.parse(target, fmt2);
System.out.println("ofPattern() :" + dt2);
}
}
執行結果
now() :2021-02-25T19:34:43.799818400
ISO_DATE :2021-02-25
ofPattern() :2021-02-25T21:03:20
說明
ISO_DATE是標準的日期格式,使用DateTimeFormatter.format()方法將目標日期修改為標準格式。
自訂格式可用DateTimeFormatter.ofPattern()方法來製作。
再用LocalDateTime.parse(目標日期,自訂格式)來套用格式。
日期時間計算範例
import java.time.LocalDate;
class Sample7_9 {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2020,02,25);
System.out.println("date :" + date);
System.out.println("After 3 day :" + date.plusDays(3));
System.out.println("After 5 months :" + date.plusMonths(5));
System.out.println("After 2 weeks :" + date.plusWeeks(2));
System.out.println("After 10 years :" + date.plusYears(10));
}
}
執行結果
date :2020-02-25
After 3 day :2020-02-28
After 5 months :2020-07-25
After 2 weeks :2020-03-10
After 10 years :2030-02-25
函數型interface
定義的抽象方法只有一個(包含static及default方法)的interface,稱為函數型interface。
Lambda式
有些class只使用一次而不會在其他地方使用,此時可以不用特別定義class,而採用Lambda式來處理,文法如下:
{引數} -> {處理};
處理後的返回值,會被丟給函數型interface承接。
※函數型interface意指只含有一個抽象方法(或是static,default方法)的interface
請看下例:
import java.util.function.Function;
public class Sample7_10 {
public static void main(String[] args) {
Function<String, String> obj = (String str) -> {
return "Hello " + str;
};
String str = obj.apply("Tom");
System.out.println(str);
}
}
執行結果
Hello Tom
此範例中,從Function<String, String> obj 開始的三行程式碼,相當於class定義。
在這個匿名class(沒有名字的class)中使用了Lambda式{引數} -> {處理},然後把返回值丟給Function<String, String> obj。
Function是一個JAVA提供的函數型interface,因此裡面只有一個抽象方法叫做apply()。
我們在Lambda式裡面把這個抽象方法給覆寫了,內容就是return "Hello " + str;
因此,當obj.apply()方法被執行時,"Tom"作為引數被丟進方法裡,加工後返回。
※Function<String, String>的意思是Function<引數的型態, 返回值的型態>
JAVA SE8導入了以下幾個函數型interface,有興趣可以google一下。
Function<T,R>
Consumer
Predicate
Supplier
UnaryOperator
另外Lambda式還有各式各樣的簡寫,範例如下:
未簡寫
(String str) ->
省略資料型態(因為interface那邊已經宣告過了)
(str) ->
省略括號(引數只有一個時可省略)
str ->
沒有引數的時候
() ->
接下來看->右邊的簡寫
未簡寫
{
return "Hello" + str;
}
省略中括號和retrun(處理只有一行時)
"Hello" + str;
簡寫後的範例如下:
import java.util.function.Function;
public class Sample7_10 {
public static void main(String[] args) {
//函數型interface<T,R> obj = 引數 -> 處理內容;
Function<String, String> obj = str -> "Hello " + str;
String str = obj.apply("Tom");
System.out.println(str);
}
}
再來看看其他函數型interface的使用範例吧
import java.util.*;
import java.util.function.*;
public class Sample7_11 {
public static void main(String[] args) {
List<String> words = Arrays.asList("Tom","Mary");
words.replaceAll( str -> str.toUpperCase());
System.out.println(words);
}
}
執行結果
[TOM, MARY]
※replaceAll()是List interface提供的default方法
import java.util.*;
import java.util.function.*;
public class Sample7_12 {
public static void main(String[] args) {
List<Integer> data = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
data.removeIf( i -> i % 2 != 0);
System.out.println(data);
}
}
執行結果
[2, 4]
※removeIf是Collection提供的default方法
以上是第七章 API的學習心得,下一章會介紹例外的處理。
參考教材: JAVAプログラマSilver SE8 - 山本 道子